package com.gjintel.workflow.trade.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.NativeTaskQuery;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.gjintel.framework.user.model.User;
import com.gjintel.framework.util.CommUtil;
import com.gjintel.sdk.base.dao.Page;
import com.gjintel.workflow.trade.dto.ProcessDefinitionDto;

/**
 * 外置表单Controller
 * 了解不同表单请访问：http://www.kafeitu.me/activiti/2012/08/05/diff-activiti
 * -workflow-forms.html
 * 
 * @author HenryYan
 */
@Controller
@RequestMapping(value = "/form/formkey")
public class FormKeyController {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private RepositoryService repositoryService;

	@Autowired
	private FormService formService;

	@Autowired
	private TaskService taskService;

	@Autowired
	private IdentityService identityService;

	@Autowired
	private HistoryService historyService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private ManagementService managementService;

	/**
	 * 动态form流程列表
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "/processlist")
	@ResponseBody
	public JSONObject processDefinitionList(
			Model model,
			@RequestParam(value = "processType", required = false) String processType,
			HttpServletRequest request, Page page) {

		// 只读取动态表单：leave-formkey
		ProcessDefinitionQuery query = repositoryService
				.createProcessDefinitionQuery().processDefinitionKey(
						"leave-formkey").active().orderByDeploymentId().desc();
		List<ProcessDefinition> queryList = query.listPage(page.getFirst() - 1,
				page.getPageSize());

		List<ProcessDefinitionDto> result = new ArrayList<ProcessDefinitionDto>();
		// 分页数据处理
		for (ProcessDefinition pd : queryList) {
			ProcessDefinitionDto dto = new ProcessDefinitionDto();
			dto.setId(pd.getId());
			dto.setDeploymentId(pd.getDeploymentId());
			dto.setKey(pd.getKey());
			dto.setName(pd.getName());
			dto.setVersion(pd.getVersion());
			dto.setResourceName(pd.getResourceName());
			dto.setDiagramResourceName(pd.getDiagramResourceName());
			result.add(dto);
		}
		page.setResult(result);
		page.setTotalCount(query.count());

		return CommUtil.getPageJSONData(page, true);
	}

	/**
	 * 初始化启动流程，读取启动流程的表单内容来渲染start form
	 */
	@RequestMapping(value = "get-form/start/{processDefinitionId}")
	@ResponseBody
	public Object findStartForm(
			@PathVariable("processDefinitionId") String processDefinitionId)
			throws Exception {

		// 根据流程定义ID读取外置表单
		Object startForm = formService.getRenderedStartForm(processDefinitionId);

		return startForm;
	}

	/**
	 * 读取Task的表单
	 */
	@RequestMapping(value = "get-form/task/{taskId}")
	@ResponseBody
	public Object findTaskForm(@PathVariable("taskId") String taskId)
			throws Exception {
		Object renderedTaskForm = formService.getRenderedTaskForm(taskId);
		return renderedTaskForm;
	}

	/**
	 * 办理任务，提交task的并保存form
	 */
	@RequestMapping(value = "task/complete/{taskId}")
	@ResponseBody
	public boolean completeTask(@PathVariable("taskId") String taskId,
			RedirectAttributes redirectAttributes, HttpServletRequest request,HttpSession session) {
		 Map<String, String> formProperties = new HashMap<String, String>();
		
		 // 从request中读取参数然后转换
		 Map<String, String[]> parameterMap = request.getParameterMap();
		 Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
		 for (Entry<String, String[]> entry : entrySet) {
			 String key = entry.getKey();
			 /*
			 * 参数结构：fq_reason，用_分割 fp的意思是form paremeter 最后一个是属性名称
			 */
			 if (StringUtils.defaultString(key).startsWith("fp_")) {
				 String[] paramSplit = key.split("_");
				 formProperties.put(paramSplit[1], entry.getValue()[0]);
			 }
		 }
		
		 User user = (User) session.getAttribute("loginUser");
		
		 // 用户未登录不能操作，实际应用使用权限框架实现，例如Spring Security、Shiro等
		 try {
			 identityService.setAuthenticatedUserId(user.getId());
			
			 formService.submitTaskFormData(taskId, formProperties);
		 } finally {
			 identityService.setAuthenticatedUserId(null);
		 }
		
		 return true;
	}

	/**
	 * 读取启动流程的表单字段
	 */
	@RequestMapping(value = "start-process/{processDefinitionId}")
	@SuppressWarnings("unchecked")
	@ResponseBody
	public boolean submitStartFormAndStartProcessInstance(
			@PathVariable("processDefinitionId") String processDefinitionId,
			RedirectAttributes redirectAttributes, HttpServletRequest request,
			HttpSession session) {
		Map<String, String> formProperties = new HashMap<String, String>();
		// request.getParameterNames()
		// 从request中读取参数然后转换
		Map<String, String[]> parameterMap = request.getParameterMap();
		Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
		for (Entry<String, String[]> entry : entrySet) {
			String key = entry.getKey();

			// fp_的意思是form paremeter
			if (StringUtils.defaultString(key).startsWith("fp_")) {
				formProperties.put(key.split("_")[1], entry.getValue()[0]);
			}
		}
		User user = (User) session.getAttribute("loginUser");

		try {
			identityService.setAuthenticatedUserId(user.getId());

			ProcessInstance processInstance = formService.submitStartFormData(
					processDefinitionId, formProperties);
			logger.debug("start a processinstance: {}", processInstance);

		} finally {
			identityService.setAuthenticatedUserId(null);
		}

		return true;
	}

	/**
	 * task列表
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "task/list")
	public ModelAndView taskList(Model model, HttpServletRequest request,
			HttpSession session, Page page) {
		ModelAndView mav = new ModelAndView("/workflow/formkey-task-list");
		User user = (User) session.getAttribute("loginUser");
		/**
		 * 这里为了演示区分开自定义表单的请假流程，值读取leave-formkey
		 */

		// 已经签收的或者直接分配到当前人的任务
		String asigneeSql = "select distinct RES.* from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ WHERE RES.ASSIGNEE_ = #{userId}"
				+ " and D.KEY_ = #{processDefinitionKey} and RES.SUSPENSION_STATE_ = #{suspensionState}";

		// 当前人在候选人或者候选组范围之内
		String needClaimSql = "select distinct RES1.* from ACT_RU_TASK RES1 inner join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES1.ID_ inner join ACT_RE_PROCDEF D1 on RES1.PROC_DEF_ID_ = D1.ID_ WHERE"
				+ " D1.KEY_ = #{processDefinitionKey} and RES1.ASSIGNEE_ is null and I.TYPE_ = 'candidate'"
				+ " and ( I.USER_ID_ = #{userId} or I.GROUP_ID_ IN (select g.GROUP_ID_ from ACT_ID_MEMBERSHIP g where g.USER_ID_ = #{userId} ) )"
				+ " and RES1.SUSPENSION_STATE_ = #{suspensionState}";
		String sql = asigneeSql + " union all " + needClaimSql;
		NativeTaskQuery query = taskService.createNativeTaskQuery()//
											.sql(sql)//
											.parameter("processDefinitionKey", "leave-formkey")//
											.parameter("suspensionState",SuspensionState.ACTIVE.getStateCode())//
											.parameter("userId", user.getId());
		List<Task> tasks = query.listPage(page.getFirst() - 1, page.getPageSize());
		
		page.setResult(tasks);
		page.setTotalCount(query.sql("select count(*) from (" + sql +") as CT").count());
		mav.addObject("page", page);
		return mav;
	}

	/**
	 * 签收任务
	 */
	@RequestMapping(value = "task/claim/{id}")
	public String claim(@PathVariable("id") String taskId, HttpSession session,
			RedirectAttributes redirectAttributes) {
		User user = (User) session.getAttribute("loginUser");
		 taskService.claim(taskId, user.getId());
		 redirectAttributes.addFlashAttribute("message", "任务已签收");
		return "redirect:/form/formkey/task/list";
	}

	/**
	 * 运行中的流程实例
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "process-instance/running/list")
	public ModelAndView running(Model model, HttpServletRequest request,Page page) {
		ModelAndView mav = new ModelAndView("/workflow/form-running-list");
		ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery()//
		 											.processDefinitionKey("leave-formkey")//
		 											.active()//
		 											.orderByProcessInstanceId().desc();
		List<ProcessInstance> list = query.listPage(page.getFirst() - 1,page.getPageSize());
		page.setResult(list);
		page.setTotalCount(query.count());
		mav.addObject("page", page);
		return mav;
	}

	/**
	 * 已结束的流程实例
	 * 
	 * @param model
	 * @return
	 */
	@RequestMapping(value = "process-instance/finished/list")
	public ModelAndView finished(Model model, HttpServletRequest request,Page page) {
		ModelAndView mav = new ModelAndView("/workflow/form-finished-list");
		HistoricProcessInstanceQuery query =historyService.createHistoricProcessInstanceQuery()//
															 .processDefinitionKey("leave-formkey")//
															 .orderByProcessInstanceEndTime().desc()//
															 .finished();
		List<HistoricProcessInstance> list = query.listPage(page.getFirst() - 1,
					page.getPageSize());
		
		page.setResult(list);
		page.setTotalCount(query.count());
		mav.addObject("page", page);
		return mav;
	}

	@RequestMapping(value = "/test", method = RequestMethod.POST)
	public ModelAndView test(HttpServletRequest request, String name) {
		// request.getAttribute("fp_leaveType")
		ModelAndView mv = new ModelAndView("http://www.baidu.com");
		System.out.println("FormKeyController.test()");
		request.getAttribute("fp_leaveType");
		return mv;
	}
}
